package cn.dduan.fool.design.pattern.structure.bring;

/**
 * 桥接模式
 * <p>
 * 核心：
 * 1、通过提供抽象化和实现化之间的桥接结构，来实现二者的解耦
 * 2、把抽象(abstraction)与行为实现(implementation)分离开来，从而可以保持各部分的独立性以及应对它们的功能扩展
 * <p>
 * 优点：
 * 1、桥接模式可以取代多层继承的方案。 多层继承违背了单一职责原则，复用性较差，类的个数也非常多。桥接模式可以极大的减少子类的个数，从而降低管理和维护的成本
 * 2、桥接模式极大的提高了系统可扩展性，在两个变化维度中任意扩展一个维度，都不需要修改原有的系统，符合开闭原则
 * <p>
 * 缺点：
 * 1、会增加系统的理解与设计难度，由于关联关系建立在抽象层，要求开发者一开始就针对抽象层进行设计与编程
 * 2、正确识别出系统中两个独立变化的维度并不是一件容易的事情
 * <p>
 * 应用场景：
 * 1、当一个类存在两个独立变化的维度，且这两个维度都需要进行扩展时
 * 2、当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时
 * 3、当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
public class BringPattern {
    public static void main(String[] args) {
        // 蛋糕
        Food cake = new Cake();
        // 芒果
        Fruit mango = new Mango();
        // 牛奶
        Food milk = new Milk();

        cake.setFruit(mango);
        cake.add();
        milk.setFruit(mango);
        milk.add();
    }
}

/**
 * 食品类 ｜ 抽象类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
abstract class Food {
    /**
     * 水果
     */
    Fruit fruit;

    public void setFruit(Fruit fruit) {
        this.fruit = fruit;
    }

    /**
     * 制作时添加
     */
    public abstract void add();
}

/**
 * 蛋糕 ｜ 扩充抽象类（子类）
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
class Cake extends Food {

    @Override
    public void add() {
        fruit.beAdd("蛋糕");
    }
}

/**
 * 牛奶 ｜ 扩充抽象类（子类）
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
class Milk extends Food {
    @Override
    public void add() {
        fruit.beAdd("牛奶");
    }
}

/**
 * 水果接口类 ｜ 实现类接口
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
interface Fruit {
    /**
     * 被添加
     *
     * @param food
     */
    public void beAdd(String food);
}

/**
 * 香蕉 ｜ 具体实现类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
class Banana implements Fruit {
    @Override
    public void beAdd(String food) {
        System.out.println("香蕉" + food);
    }
}

/**
 * 芒果 ｜ 具体实现类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/7
 */
class Mango implements Fruit {
    @Override
    public void beAdd(String food) {
        System.out.println("芒果" + food);
    }
}